#coding=utf8


class Middleware(object):
    def before_request(self):
        pass

    def after_request(self, response):
        return response


class DynMiddleware(Middleware):
    def __init__(self, before_fn=None, after_fn=None):
        self.before_fn = before_fn
        self.after_fn = after_fn

    def before_request(self):
        if self.before_fn:
            return self.before_fn()

    def after_request(self, response):
        if self.after_fn:
            return self.after_fn(response)
        else:
            return response


class FlaskMiddlewares(object):
    def __init__(self, app=None):
        if app is not None:
            self.init_app(app)

        self.mws = []
        self.rmws = []

    def init_app(self, app):
        if 'middlewares' in app.extensions:
            raise Exception('flask_middlewares already registered')

        app.extensions['middlewares'] = self

        app.before_request(self.before_request)
        app.after_request(self.after_request)

    def before_request(self):
        for mw in self.mws:
            rv = mw.before_request()
            if rv is not None:
                return rv

    def after_request(self, response):
        for mw in self.rmws:
            response = mw.after_request(response)

        return response
        
    def register(self, mw):
        if not isinstance(mw, Middleware):
            raise TypeError("mw must be Middleware")

        self.mws.append(mw)
        self.rmws.insert(0, mw)

    def register_before_request(self, fn):
        if not callable(fn):
            raise TypeError("mw must be callable")

        mw = DynMiddleware(before_fn=fn)
        self.register(mw)

    def register_after_request(self, fn):
        if not callable(fn):
            raise TypeError("mw must be callable")

        mw = DynMiddleware(after_fn=fn)
        self.register(mw)
